winbrew_windows\deployment\msi/
mod.rs1#![cfg(windows)]
2#![doc = include_str!("README.md")]
3
4use anyhow::Result;
5use std::path::Path;
6
7use crate::models::install::engine::InstallScope;
8use crate::models::msi_inventory::records::{MsiInventoryReceipt, MsiInventorySnapshot};
9
10mod builder;
11mod database;
12mod directory;
13mod path;
14
15use self::{
16 builder::{
17 build_component_records, build_file_paths, build_file_records, build_registry_records,
18 build_shortcut_records,
19 },
20 database::{
21 MsiDatabase, load_component_rows, load_directory_rows, load_file_rows, load_registry_rows,
22 load_shortcut_rows, query_optional_string, query_required_string,
23 },
24 directory::resolve_directory_paths,
25};
26
27pub fn scan_inventory(
33 package_path: &Path,
34 install_root: &Path,
35 package_name: &str,
36 scope: InstallScope,
37) -> Result<MsiInventorySnapshot> {
38 let database = MsiDatabase::open(package_path)?;
39
40 let product_code = query_required_string(
41 database.handle(),
42 "SELECT `Value` FROM `Property` WHERE `Property` = 'ProductCode'",
43 )?;
44 let upgrade_code = query_optional_string(
45 database.handle(),
46 "SELECT `Value` FROM `Property` WHERE `Property` = 'UpgradeCode'",
47 )?;
48
49 let directory_rows = load_directory_rows(database.handle())?;
50 let component_rows = load_component_rows(database.handle())?;
51 let file_rows = load_file_rows(database.handle())?;
52 let registry_rows = load_registry_rows(database.handle())?;
53 let shortcut_rows = load_shortcut_rows(database.handle())?;
54
55 let directory_paths = resolve_directory_paths(&directory_rows, install_root)?;
56 let file_paths = build_file_paths(&file_rows, &component_rows, &directory_paths, install_root);
57
58 let files = build_file_records(
59 package_name,
60 &file_rows,
61 &file_paths,
62 &component_rows,
63 &directory_paths,
64 install_root,
65 );
66 let registry_entries = build_registry_records(package_name, scope, ®istry_rows);
67 let shortcuts = build_shortcut_records(
68 package_name,
69 &shortcut_rows,
70 &directory_paths,
71 &file_paths,
72 install_root,
73 );
74 let components =
75 build_component_records(package_name, &component_rows, &directory_paths, &file_paths);
76
77 Ok(MsiInventorySnapshot {
78 receipt: MsiInventoryReceipt {
79 package_name: package_name.to_string(),
80 product_code,
81 upgrade_code,
82 scope,
83 },
84 files,
85 registry_entries,
86 shortcuts,
87 components,
88 })
89}
90
91#[derive(Debug, Clone)]
92struct DirectoryRow {
93 parent: Option<String>,
94 default_dir: String,
95}
96
97#[derive(Debug, Clone)]
98struct ComponentRow {
99 directory_id: String,
100 key_path: Option<String>,
101}
102
103#[derive(Debug, Clone)]
104struct FileRow {
105 file_key: String,
106 component_id: String,
107 file_name: String,
108}
109
110#[derive(Debug, Clone)]
111struct RegistryRow {
112 root: i32,
113 key_path: String,
114 name: Option<String>,
115 value: Option<String>,
116}
117
118#[derive(Debug, Clone)]
119struct ShortcutRow {
120 directory_id: String,
121 name: String,
122 target: String,
123}